Add analyzer section in project.assets.json file - #7464
Merged
Conversation
jebriede
previously approved these changes
Jun 9, 2026
jebriede
left a comment
Contributor
There was a problem hiding this comment.
Approving with a few suggestions.
jebriede
previously approved these changes
Jun 15, 2026
jebriede
left a comment
Contributor
There was a problem hiding this comment.
Approving with an optimization suggestion.
nkolev92
reviewed
Jun 16, 2026
nkolev92
left a comment
Member
There was a problem hiding this comment.
I think we're introducing a new implementation pattern in a couple of different places, but we already have an established one.
martinrrm
force-pushed
the
dev-mruizmares-analyzer-assets
branch
2 times, most recently
from
June 26, 2026 00:42
963cbee to
b7099ed
Compare
nkolev92
reviewed
Jun 30, 2026
martinrrm
added a commit
that referenced
this pull request
Jun 30, 2026
Address PR feedback (#7464): use the NoAllocEnumerate helper for the IList iterations in PopulateAnalyzerAssetsTelemetry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
martinrrm
added a commit
that referenced
this pull request
Jun 30, 2026
Address PR feedback (#7464): look up TargetFrameworkInformation by (framework, alias) via GetNearestTargetFramework instead of framework-only, in LockFileBuilder and the analyzer-assets telemetry, so multi-targeted projects with aliased frameworks resolve to the correct target framework. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
martinrrm
added a commit
that referenced
this pull request
Jun 30, 2026
Address PR feedback (#7464): treat RestoreEnableAnalyzerAssets as a project-wide opt-in instead of per target framework. When any target framework opts in, analyzer assets are honored for every target framework, mirroring how package pruning is enabled project-wide once any framework qualifies (PackageSpecFactory.GetPackagePruningDefault). The per-framework opt-in is already gated to .NET 11+ in NuGet.targets, so only a qualifying framework can enable it. Add a multi-targeted restore test asserting a non-opted-in framework still honors analyzers when another framework opts in. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
martinrrm
added a commit
that referenced
this pull request
Jul 2, 2026
Address PR feedback (#7464): analyzer assets restore was force-disabled below .NET 11 even when explicitly opted in. Mirror package pruning instead — default to off, but honor an explicit RestoreEnableAnalyzerAssets opt-in (or opt-out) on any target framework, so users can opt into the new behavior before it is enabled by default. The net11 version gate only ever forced off the explicit opt-in; a future default-on can gate itself the way RestorePackagePruningDefault does. Update the availability tests: the opt-in is now honored on all frameworks, and the value defaults to false when unset. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nkolev92
reviewed
Jul 6, 2026
nkolev92
previously approved these changes
Jul 16, 2026
…ventions detection Move the RestoreEnableAnalyzerAssets opt-in gating into code, per target framework. The value now flows through TargetFrameworkInformation and is read by every restore entry point, including static-graph restore which previously ignored the property entirely. Removes the project-level ProjectRestoreMetadata.RestoreEnableAnalyzerAssets and the NuGet.targets OR. Detect analyzers via a new AnalyzerAssemblies pattern in ManagedCodeConventions instead of the hand-rolled IsAnalyzerAssetPath, so detection is shared with the content model and matches the analyzers folder case-insensitively. Clarify the analyzer metadata derivation comment and trim an allocation in the compiler-version normalization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add five properties to the ProjectRestoreInformation event to size the impact of enabling RestoreEnableAnalyzerAssets by default before the rollout: - AnalyzerAssets.Excluded.Count - AnalyzerAssets.PackagesWithAnalyzers.Count - AnalyzerAssets.PackagesWithExcludedAnalyzers.Count - AnalyzerAssets.ExcludedByPrivateAssets.Count - AnalyzerAssets.ExcludedByExcludeAssets.Count The counts are derived from the resolved dependency graphs and the package file lists, so they are reported on every full restore regardless of whether the feature is currently enabled. This lets us measure how many packages and analyzer assemblies would stop being applied once PrivateAssets/ExcludeAssets are honored. AnalyzerAssets.Count is redefined as the number of analyzer assemblies that would apply (computed the same way), replacing the previous count of analyzer assets written to the assets file. Analyzer detection mirrors ManagedCodeConventions.ManagedCodePatterns. AnalyzerAssemblies as a cheap string check, avoiding a content-item collection allocation per package on the restore path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address spec review feedback (Client.Engineering#3855): the rollout decision is driven by whether a package's analyzers are affected, not by how many individual analyzer assemblies it ships. - Remove AnalyzerAssets.Count (per-assembly applied count). - Replace AnalyzerAssets.Excluded.Count with a binary AnalyzerAssets.Excluded (true when any package's analyzers would be filtered out for the project). The package-level counts (PackagesWithAnalyzers.Count, PackagesWithExcludedAnalyzers.Count, ExcludedByPrivateAssets.Count, ExcludedByExcludeAssets.Count) are unchanged. Per-package detection now uses a HashSet rather than per-assembly counts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR feedback (#7464): use the NoAllocEnumerate helper for the IList iterations in PopulateAnalyzerAssetsTelemetry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR feedback (#7464): look up TargetFrameworkInformation by (framework, alias) via GetNearestTargetFramework instead of framework-only, in LockFileBuilder and the analyzer-assets telemetry, so multi-targeted projects with aliased frameworks resolve to the correct target framework. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR feedback (#7464): treat RestoreEnableAnalyzerAssets as a project-wide opt-in instead of per target framework. When any target framework opts in, analyzer assets are honored for every target framework, mirroring how package pruning is enabled project-wide once any framework qualifies (PackageSpecFactory.GetPackagePruningDefault). The per-framework opt-in is already gated to .NET 11+ in NuGet.targets, so only a qualifying framework can enable it. Add a multi-targeted restore test asserting a non-opted-in framework still honors analyzers when another framework opts in. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR feedback (#7464): analyzer assets restore was force-disabled below .NET 11 even when explicitly opted in. Mirror package pruning instead — default to off, but honor an explicit RestoreEnableAnalyzerAssets opt-in (or opt-out) on any target framework, so users can opt into the new behavior before it is enabled by default. The net11 version gate only ever forced off the explicit opt-in; a future default-on can gate itself the way RestorePackagePruningDefault does. Update the availability tests: the opt-in is now honored on all frameworks, and the value defaults to false when unset. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RestoreEnableAnalyzerAssets was stored per target framework on TargetFrameworkInformation, but analyzer assets are a project-wide opt-in. Move it to ProjectRestoreMetadata (mirroring UsingMicrosoftNETSdk / RestoreUseLegacyDependencyResolver / RestoreDoNotWriteDependencyGraphSpec) so consumers read a single project-level value instead of scanning every target framework. - Model: add the property (plus Equals/GetHashCode/Clone) to ProjectRestoreMetadata and remove it from TargetFrameworkInformation. - Serialization: read and write it under the "restore" metadata section. - Readers: PackageSpecFactory, MSBuildStaticGraphRestore and MSBuildRestoreUtility now set it at the project level. - LockFileBuilder and restore telemetry read the project-level value directly. - NuGet.targets: emit RestoreEnableAnalyzerAssets on the ProjectSpec restore graph entry (not the per-framework entry) so the task-based restore path captures the opt-in; add a GenerateRestoreGraphFile functional test covering both the standard and static-graph evaluation paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve target framework information by alias instead of selecting a nearest framework. Keep warning and dependency alias handling safe when no exact framework metadata exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1c3025b-91e0-4a52-9c20-8162710176f6
Exercise LockFileBuilder with a target graph alias that is absent from the PackageSpec so exact alias lookup remains null-safe. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1c3025b-91e0-4a52-9c20-8162710176f6
Preserve project-wide analyzer behavior after moving the setting to restore metadata. Promote an enabled outer or inner build consistently across standard, PackageSpecFactory, and static graph restore paths. Add focused unit coverage and an SDK-next NET10/NET11 restore matrix that verifies analyzers are written for every target framework. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1c3025b-91e0-4a52-9c20-8162710176f6
Run the multi-target analyzer assets test on the default SDK 11 test target and align its name with the project-wide opt-in scenario. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: dc2642ca-597e-4ac9-b965-80b0fbd3b338
martinrrm
force-pushed
the
dev-mruizmares-analyzer-assets
branch
from
July 17, 2026 17:04
58a73e1 to
ca6deb2
Compare
nkolev92
approved these changes
Jul 17, 2026
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
Progress: NuGet/Home#6279
SDK PR (draft): dotnet/sdk#54646
Description
Today
project.assets.jsondoes not record which analyzers a package contributes, and analyzers are applied regardless ofPrivateAssets/ExcludeAssets/IncludeAssets. This PR implements the NuGet restore half of the "indicate analyzer assets in project.assets.json" feature (spec: NuGet/Home#14455). The SDK consumption half ships as a separate dotnet/sdk PR.When a project opts in with
<RestoreEnableAnalyzerAssets>true</RestoreEnableAnalyzerAssets>, restore now:analyzersgroup under each package in the assets file, listing every analyzer assembly. Detection uses a newAnalyzerAssembliespattern inManagedCodeConventions(any.dllunderanalyzers/at any depth, excluding satellite.resources.dll), so the layout isn't assumed to be fixed and analyzer discovery is shared with the rest of the content model.PrivateAssets,ExcludeAssets, andIncludeAssetsfilter analyzers like any other asset type. Analyzers excluded or transitively suppressed are written as a_._placeholder (consistent withcompile/runtime/native).codeLanguage(cs/vb/fs/any) and, when present in the path,compilerApiVersion(roslynX.Y) — mirroring how content files carrycodeLanguage— so the SDK selects applicable analyzers from metadata instead of parsing paths. The metadata is derived by scanning the path segments, since real packages place the language at a variable depth (for exampleanalyzers/dotnet/roslynX.Y/cs/).Gating. The feature is opt-in and only honored for projects targeting .NET 11 or greater. The
.NET 11+gate is applied at evaluation time inNuGet.targets(mirroringNuGetAuditMode), and the resulting value is honored per target framework: it flows throughTargetFrameworkInformation.RestoreEnableAnalyzerAssetsand is read in code by every restore entry point — CLI/DG-spec (MSBuildRestoreUtility), VS nomination (PackageSpecFactory), and static-graph restore (MSBuildStaticGraphRestore, which previously did not honor the property at all). A multi-targetednet10.0;net11.0project therefore emits theanalyzersgroup only fornet11.0.Telemetry.
ProjectRestoreInformationreportsAnalyzerAssets.Enabled(opt-in state) andAnalyzerAssets.Count(number of analyzer assets emitted, excluding_._placeholders). Richer adoption/impact telemetry to inform the default-on rollout ships as a follow-up.Public API & serialization. Adds
TargetFrameworkInformation.RestoreEnableAnalyzerAssets,LockFileTargetLibrary.AnalyzerAssets,LockFileItem.CompilerApiVersionProperty, and theManagedCodeConventions.ManagedCodePatterns.AnalyzerAssembliespattern (with theAnalyzerAssemblyproperty name). The Newtonsoft.Json and System.Text.Json paths round-trip the newanalyzersgroup and its metadata; the per-framework restore property round-trips throughPackageSpecWriterand the streaming reader. The lock-file cache key includes the per-framework flag so toggling it invalidates correctly.PR Checklist